﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace DZPK.SocketImpl
{

    public class TcpSocket 
    {
        public const int REQ_REQUEST = 0;
        public const int REQ_HEADER = 1;
        public const int REQ_BODY = 2;
        public const int REQ_DONE = 3;
        public const int REQ_PROCESS = 4;
        public const int REQ_ERROR = 5;
        public const int PACKET_HEADER_SIZE = 13;
        public const int ERL_PACKET_HEADER_SIZE = 9;
        public const int PACKET_BUFFER_SIZE = 0x4000;

        private SocketWrapper socket = null;
        public Socket GetSocketInstance()
        {
            return socket != null ? socket.sender : null;
        }
        private ByteArray packet= null;  // byte array in as 3.
        private uint packetlen = 0;
        private ByteArray packetbody = null;
        private ByteArray readpacket = null;
        private int nStatus = 0;
        private int nreadPos = 0;
        private uint nBodyLen = 0;
        private int enCode = 0;
        private int ndx = 0;
        private int sequence = 0;
        private string _host = "";
        private int _port = 0;
        private bool _connected = false;
        public ByteArray m_SendByteMap = null;
        public ByteArray m_RecvByteMap = null;
        private int readbodypos = 13;

        private Task ReceiveServerDataTask = null;
        private bool bReceiveTaskStarted = false;

        private Player player = null;
        private ProcessCMD cmdProcessor = null;

        public static void InitEncrypt(ByteArray _arg1,  ByteArray _arg2)
        {
                _arg1.writeByte(112);
                _arg1.writeByte(47);
                _arg1.writeByte(64);
                _arg1.writeByte(95);
                _arg1.writeByte(68);
                _arg1.writeByte(142);
                _arg1.writeByte(110);
                _arg1.writeByte(69);
                _arg1.writeByte(126);
                _arg1.writeByte(171);
                _arg1.writeByte(44);
                _arg1.writeByte(31);
                _arg1.writeByte(180);
                _arg1.writeByte(172);
                _arg1.writeByte(157);
                _arg1.writeByte(145);
                _arg1.writeByte(13);
                _arg1.writeByte(54);
                _arg1.writeByte(155);
                _arg1.writeByte(11);
                _arg1.writeByte(212);
                _arg1.writeByte(196);
                _arg1.writeByte(57);
                _arg1.writeByte(116);
                _arg1.writeByte(191);
                _arg1.writeByte(35);
                _arg1.writeByte(22);
                _arg1.writeByte(20);
                _arg1.writeByte(6);
                _arg1.writeByte(235);
                _arg1.writeByte(4);
                _arg1.writeByte(62);
                _arg1.writeByte(18);
                _arg1.writeByte(92);
                _arg1.writeByte(139);
                _arg1.writeByte(188);
                _arg1.writeByte(97);
                _arg1.writeByte(99);
                _arg1.writeByte(246);
                _arg1.writeByte(165);
                _arg1.writeByte(225);
                _arg1.writeByte(101);
                _arg1.writeByte(216);
                _arg1.writeByte(245);
                _arg1.writeByte(90);
                _arg1.writeByte(7);
                _arg1.writeByte(240);
                _arg1.writeByte(19);
                _arg1.writeByte(242);
                _arg1.writeByte(32);
                _arg1.writeByte(107);
                _arg1.writeByte(74);
                _arg1.writeByte(36);
                _arg1.writeByte(89);
                _arg1.writeByte(137);
                _arg1.writeByte(100);
                _arg1.writeByte(215);
                _arg1.writeByte(66);
                _arg1.writeByte(106);
                _arg1.writeByte(94);
                _arg1.writeByte(61);
                _arg1.writeByte(10);
                _arg1.writeByte(119);
                _arg1.writeByte(224);
                _arg1.writeByte(128);
                _arg1.writeByte(39);
                _arg1.writeByte(184);
                _arg1.writeByte(197);
                _arg1.writeByte(140);
                _arg1.writeByte(14);
                _arg1.writeByte(250);
                _arg1.writeByte(138);
                _arg1.writeByte(213);
                _arg1.writeByte(41);
                _arg1.writeByte(86);
                _arg1.writeByte(87);
                _arg1.writeByte(108);
                _arg1.writeByte(83);
                _arg1.writeByte(103);
                _arg1.writeByte(65);
                _arg1.writeByte(232);
                _arg1.writeByte(0);
                _arg1.writeByte(26);
                _arg1.writeByte(206);
                _arg1.writeByte(134);
                _arg1.writeByte(131);
                _arg1.writeByte(176);
                _arg1.writeByte(34);
                _arg1.writeByte(40);
                _arg1.writeByte(77);
                _arg1.writeByte(63);
                _arg1.writeByte(38);
                _arg1.writeByte(70);
                _arg1.writeByte(79);
                _arg1.writeByte(111);
                _arg1.writeByte(43);
                _arg1.writeByte(114);
                _arg1.writeByte(58);
                _arg1.writeByte(241);
                _arg1.writeByte(141);
                _arg1.writeByte(151);
                _arg1.writeByte(149);
                _arg1.writeByte(73);
                _arg1.writeByte(132);
                _arg1.writeByte(229);
                _arg1.writeByte(227);
                _arg1.writeByte(121);
                _arg1.writeByte(143);
                _arg1.writeByte(81);
                _arg1.writeByte(16);
                _arg1.writeByte(168);
                _arg1.writeByte(130);
                _arg1.writeByte(198);
                _arg1.writeByte(221);
                _arg1.writeByte(0xFF);
                _arg1.writeByte(252);
                _arg1.writeByte(228);
                _arg1.writeByte(207);
                _arg1.writeByte(179);
                _arg1.writeByte(9);
                _arg1.writeByte(93);
                _arg1.writeByte(234);
                _arg1.writeByte(156);
                _arg1.writeByte(52);
                _arg1.writeByte(249);
                _arg1.writeByte(23);
                _arg1.writeByte(159);
                _arg1.writeByte(218);
                _arg1.writeByte(135);
                _arg1.writeByte(248);
                _arg1.writeByte(21);
                _arg1.writeByte(5);
                _arg1.writeByte(60);
                _arg1.writeByte(211);
                _arg1.writeByte(164);
                _arg1.writeByte(133);
                _arg1.writeByte(46);
                _arg1.writeByte(251);
                _arg1.writeByte(238);
                _arg1.writeByte(71);
                _arg1.writeByte(59);
                _arg1.writeByte(239);
                _arg1.writeByte(55);
                _arg1.writeByte(127);
                _arg1.writeByte(147);
                _arg1.writeByte(175);
                _arg1.writeByte(105);
                _arg1.writeByte(12);
                _arg1.writeByte(113);
                _arg1.writeByte(49);
                _arg1.writeByte(222);
                _arg1.writeByte(33);
                _arg1.writeByte(117);
                _arg1.writeByte(160);
                _arg1.writeByte(170);
                _arg1.writeByte(186);
                _arg1.writeByte(124);
                _arg1.writeByte(56);
                _arg1.writeByte(2);
                _arg1.writeByte(183);
                _arg1.writeByte(129);
                _arg1.writeByte(1);
                _arg1.writeByte(253);
                _arg1.writeByte(231);
                _arg1.writeByte(29);
                _arg1.writeByte(204);
                _arg1.writeByte(205);
                _arg1.writeByte(189);
                _arg1.writeByte(27);
                _arg1.writeByte(122);
                _arg1.writeByte(42);
                _arg1.writeByte(173);
                _arg1.writeByte(102);
                _arg1.writeByte(190);
                _arg1.writeByte(85);
                _arg1.writeByte(51);
                _arg1.writeByte(3);
                _arg1.writeByte(219);
                _arg1.writeByte(136);
                _arg1.writeByte(178);
                _arg1.writeByte(30);
                _arg1.writeByte(78);
                _arg1.writeByte(185);
                _arg1.writeByte(230);
                _arg1.writeByte(194);
                _arg1.writeByte(247);
                _arg1.writeByte(203);
                _arg1.writeByte(125);
                _arg1.writeByte(201);
                _arg1.writeByte(98);
                _arg1.writeByte(195);
                _arg1.writeByte(166);
                _arg1.writeByte(220);
                _arg1.writeByte(167);
                _arg1.writeByte(80);
                _arg1.writeByte(181);
                _arg1.writeByte(75);
                _arg1.writeByte(148);
                _arg1.writeByte(192);
                _arg1.writeByte(146);
                _arg1.writeByte(76);
                _arg1.writeByte(17);
                _arg1.writeByte(91);
                _arg1.writeByte(120);
                _arg1.writeByte(217);
                _arg1.writeByte(177);
                _arg1.writeByte(237);
                _arg1.writeByte(25);
                _arg1.writeByte(233);
                _arg1.writeByte(161);
                _arg1.writeByte(28);
                _arg1.writeByte(182);
                _arg1.writeByte(50);
                _arg1.writeByte(153);
                _arg1.writeByte(163);
                _arg1.writeByte(118);
                _arg1.writeByte(158);
                _arg1.writeByte(123);
                _arg1.writeByte(109);
                _arg1.writeByte(154);
                _arg1.writeByte(48);
                _arg1.writeByte(214);
                _arg1.writeByte(169);
                _arg1.writeByte(37);
                _arg1.writeByte(199);
                _arg1.writeByte(174);
                _arg1.writeByte(150);
                _arg1.writeByte(53);
                _arg1.writeByte(208);
                _arg1.writeByte(187);
                _arg1.writeByte(210);
                _arg1.writeByte(200);
                _arg1.writeByte(162);
                _arg1.writeByte(8);
                _arg1.writeByte(243);
                _arg1.writeByte(209);
                _arg1.writeByte(115);
                _arg1.writeByte(244);
                _arg1.writeByte(72);
                _arg1.writeByte(45);
                _arg1.writeByte(144);
                _arg1.writeByte(202);
                _arg1.writeByte(226);
                _arg1.writeByte(88);
                _arg1.writeByte(193);
                _arg1.writeByte(24);
                _arg1.writeByte(82);
                _arg1.writeByte(254);
                _arg1.writeByte(223);
                _arg1.writeByte(104);
                _arg1.writeByte(152);
                _arg1.writeByte(84);
                _arg1.writeByte(236);
                _arg1.writeByte(96);
                _arg1.writeByte(67);
                _arg1.writeByte(15);
                _arg2.writeByte(81);
                _arg2.writeByte(161);
                _arg2.writeByte(158);
                _arg2.writeByte(176);
                _arg2.writeByte(30);
                _arg2.writeByte(131);
                _arg2.writeByte(28);
                _arg2.writeByte(45);
                _arg2.writeByte(233);
                _arg2.writeByte(119);
                _arg2.writeByte(61);
                _arg2.writeByte(19);
                _arg2.writeByte(147);
                _arg2.writeByte(16);
                _arg2.writeByte(69);
                _arg2.writeByte(0xFF);
                _arg2.writeByte(109);
                _arg2.writeByte(201);
                _arg2.writeByte(32);
                _arg2.writeByte(47);
                _arg2.writeByte(27);
                _arg2.writeByte(130);
                _arg2.writeByte(26);
                _arg2.writeByte(125);
                _arg2.writeByte(245);
                _arg2.writeByte(207);
                _arg2.writeByte(82);
                _arg2.writeByte(168);
                _arg2.writeByte(210);
                _arg2.writeByte(164);
                _arg2.writeByte(180);
                _arg2.writeByte(11);
                _arg2.writeByte(49);
                _arg2.writeByte(151);
                _arg2.writeByte(87);
                _arg2.writeByte(25);
                _arg2.writeByte(52);
                _arg2.writeByte(223);
                _arg2.writeByte(91);
                _arg2.writeByte(65);
                _arg2.writeByte(88);
                _arg2.writeByte(73);
                _arg2.writeByte(170);
                _arg2.writeByte(95);
                _arg2.writeByte(10);
                _arg2.writeByte(239);
                _arg2.writeByte(136);
                _arg2.writeByte(1);
                _arg2.writeByte(220);
                _arg2.writeByte(149);
                _arg2.writeByte(212);
                _arg2.writeByte(175);
                _arg2.writeByte(123);
                _arg2.writeByte(227);
                _arg2.writeByte(17);
                _arg2.writeByte(142);
                _arg2.writeByte(157);
                _arg2.writeByte(22);
                _arg2.writeByte(97);
                _arg2.writeByte(140);
                _arg2.writeByte(132);
                _arg2.writeByte(60);
                _arg2.writeByte(31);
                _arg2.writeByte(90);
                _arg2.writeByte(2);
                _arg2.writeByte(79);
                _arg2.writeByte(57);
                _arg2.writeByte(254);
                _arg2.writeByte(4);
                _arg2.writeByte(7);
                _arg2.writeByte(92);
                _arg2.writeByte(139);
                _arg2.writeByte(238);
                _arg2.writeByte(102);
                _arg2.writeByte(51);
                _arg2.writeByte(196);
                _arg2.writeByte(200);
                _arg2.writeByte(89);
                _arg2.writeByte(181);
                _arg2.writeByte(93);
                _arg2.writeByte(194);
                _arg2.writeByte(108);
                _arg2.writeByte(246);
                _arg2.writeByte(77);
                _arg2.writeByte(251);
                _arg2.writeByte(174);
                _arg2.writeByte(74);
                _arg2.writeByte(75);
                _arg2.writeByte(243);
                _arg2.writeByte(53);
                _arg2.writeByte(44);
                _arg2.writeByte(202);
                _arg2.writeByte(33);
                _arg2.writeByte(120);
                _arg2.writeByte(59);
                _arg2.writeByte(3);
                _arg2.writeByte(253);
                _arg2.writeByte(36);
                _arg2.writeByte(189);
                _arg2.writeByte(37);
                _arg2.writeByte(55);
                _arg2.writeByte(41);
                _arg2.writeByte(172);
                _arg2.writeByte(78);
                _arg2.writeByte(249);
                _arg2.writeByte(146);
                _arg2.writeByte(58);
                _arg2.writeByte(50);
                _arg2.writeByte(76);
                _arg2.writeByte(218);
                _arg2.writeByte(6);
                _arg2.writeByte(94);
                _arg2.writeByte(0);
                _arg2.writeByte(148);
                _arg2.writeByte(96);
                _arg2.writeByte(236);
                _arg2.writeByte(23);
                _arg2.writeByte(152);
                _arg2.writeByte(215);
                _arg2.writeByte(62);
                _arg2.writeByte(203);
                _arg2.writeByte(106);
                _arg2.writeByte(169);
                _arg2.writeByte(217);
                _arg2.writeByte(156);
                _arg2.writeByte(187);
                _arg2.writeByte(8);
                _arg2.writeByte(143);
                _arg2.writeByte(64);
                _arg2.writeByte(160);
                _arg2.writeByte(111);
                _arg2.writeByte(85);
                _arg2.writeByte(103);
                _arg2.writeByte(135);
                _arg2.writeByte(84);
                _arg2.writeByte(128);
                _arg2.writeByte(178);
                _arg2.writeByte(54);
                _arg2.writeByte(71);
                _arg2.writeByte(34);
                _arg2.writeByte(68);
                _arg2.writeByte(99);
                _arg2.writeByte(5);
                _arg2.writeByte(107);
                _arg2.writeByte(240);
                _arg2.writeByte(15);
                _arg2.writeByte(199);
                _arg2.writeByte(144);
                _arg2.writeByte(197);
                _arg2.writeByte(101);
                _arg2.writeByte(226);
                _arg2.writeByte(100);
                _arg2.writeByte(250);
                _arg2.writeByte(213);
                _arg2.writeByte(219);
                _arg2.writeByte(18);
                _arg2.writeByte(122);
                _arg2.writeByte(14);
                _arg2.writeByte(216);
                _arg2.writeByte(126);
                _arg2.writeByte(153);
                _arg2.writeByte(209);
                _arg2.writeByte(232);
                _arg2.writeByte(214);
                _arg2.writeByte(134);
                _arg2.writeByte(39);
                _arg2.writeByte(191);
                _arg2.writeByte(193);
                _arg2.writeByte(110);
                _arg2.writeByte(222);
                _arg2.writeByte(154);
                _arg2.writeByte(9);
                _arg2.writeByte(13);
                _arg2.writeByte(171);
                _arg2.writeByte(225);
                _arg2.writeByte(145);
                _arg2.writeByte(86);
                _arg2.writeByte(205);
                _arg2.writeByte(179);
                _arg2.writeByte(118);
                _arg2.writeByte(12);
                _arg2.writeByte(195);
                _arg2.writeByte(211);
                _arg2.writeByte(159);
                _arg2.writeByte(66);
                _arg2.writeByte(182);
                _arg2.writeByte(155);
                _arg2.writeByte(229);
                _arg2.writeByte(35);
                _arg2.writeByte(167);
                _arg2.writeByte(173);
                _arg2.writeByte(24);
                _arg2.writeByte(198);
                _arg2.writeByte(244);
                _arg2.writeByte(184);
                _arg2.writeByte(190);
                _arg2.writeByte(21);
                _arg2.writeByte(67);
                _arg2.writeByte(112);
                _arg2.writeByte(224);
                _arg2.writeByte(231);
                _arg2.writeByte(188);
                _arg2.writeByte(241);
                _arg2.writeByte(186);
                _arg2.writeByte(165);
                _arg2.writeByte(166);
                _arg2.writeByte(83);
                _arg2.writeByte(117);
                _arg2.writeByte(228);
                _arg2.writeByte(235);
                _arg2.writeByte(230);
                _arg2.writeByte(133);
                _arg2.writeByte(20);
                _arg2.writeByte(72);
                _arg2.writeByte(221);
                _arg2.writeByte(56);
                _arg2.writeByte(42);
                _arg2.writeByte(204);
                _arg2.writeByte(127);
                _arg2.writeByte(177);
                _arg2.writeByte(192);
                _arg2.writeByte(113);
                _arg2.writeByte(150);
                _arg2.writeByte(248);
                _arg2.writeByte(63);
                _arg2.writeByte(40);
                _arg2.writeByte(242);
                _arg2.writeByte(105);
                _arg2.writeByte(116);
                _arg2.writeByte(104);
                _arg2.writeByte(183);
                _arg2.writeByte(163);
                _arg2.writeByte(80);
                _arg2.writeByte(208);
                _arg2.writeByte(121);
                _arg2.writeByte(29);
                _arg2.writeByte(252);
                _arg2.writeByte(206);
                _arg2.writeByte(138);
                _arg2.writeByte(141);
                _arg2.writeByte(46);
                _arg2.writeByte(98);
                _arg2.writeByte(48);
                _arg2.writeByte(234);
                _arg2.writeByte(237);
                _arg2.writeByte(43);
                _arg2.writeByte(38);
                _arg2.writeByte(185);
                _arg2.writeByte(129);
                _arg2.writeByte(124);
                _arg2.writeByte(70);
                _arg2.writeByte(137);
                _arg2.writeByte(115);
                _arg2.writeByte(162);
                _arg2.writeByte(247);
                _arg2.writeByte(114);
        }

        public static byte EncryptBuffer(ByteArray _arg1, int _arg2, int _arg3, ByteArray _arg4)
        {
            byte _local5 = 0;
            int _local6 = _arg2;
            while (_local6 < _arg3)
            {
                _local5 += _arg1[_local6];
                // _local5;  ???
                _arg1[_local6] = MapSendByte(_arg1[_local6], _arg4);
                _local6++;
            };
            //_local5 = (~(_local5) + 1);
            int tmp = ~(_local5);
            _local5 = (byte)(tmp & 0xFF);

            _local5 += 1;
            return _local5;
        }

        public static byte MapSendByte(int _arg1, ByteArray _arg2)
        {
            return (_arg2[_arg1]);
        }

        public static byte MapRecvByte(int _arg1, ByteArray _arg2)
        {
            return (_arg2[_arg1]);
        }

        public TcpSocket(Player player)
        {
            this.socket = new SocketWrapper();
            this.packet = new ByteArray();
            this.packetbody = new ByteArray();
            this.readpacket = new ByteArray();
            this.readpacket.endian = Endian.LITTLE_ENDIAN;
            this.m_SendByteMap = new ByteArray();
            this.m_RecvByteMap = new ByteArray();
            this.player = player;
            this.cmdProcessor = new ProcessCMD(this, player);
            InitEncrypt(this.m_SendByteMap, this.m_RecvByteMap);
        }

        public Player GetPlayerInstance()
        {
            return this.player;
        }

        public void setLittleEndian()
        {
            this.packet.endian = Endian.LITTLE_ENDIAN;
            this.packetbody.endian = Endian.LITTLE_ENDIAN;
            this.m_RecvByteMap.endian = Endian.LITTLE_ENDIAN;
            this.m_SendByteMap.endian = Endian.LITTLE_ENDIAN;
        }

        public void setBigEndian()
        {
            this.packet.endian = Endian.BIG_ENDIAN;
            this.packetbody.endian = Endian.BIG_ENDIAN;
            this.m_RecvByteMap.endian = Endian.BIG_ENDIAN;
            this.m_SendByteMap.endian = Endian.BIG_ENDIAN;
        }

        public void connect(string _arg1, int _arg2)
        {
            this._host = _arg1;
            this._port = _arg2;
            if (this._connected)
            {
                this.close();
                if (bReceiveTaskStarted)
                {
                    //ReceiveServerDataTask.c
                }
            };
            this.socket = new SocketWrapper();
            this.socket.endian = Endian.LITTLE_ENDIAN;

            //  TODO:  design a event handler in the socket wrapper class.
            //this.socket.addEventListener(IOErrorEvent.IO_ERROR, this.errorFun);
            //this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityerrfun);
            //this.socket.addEventListener(Event.CONNECT, this.connectFun);
            this.socket.connect(_arg1, _arg2);
            this.sequence = 0;
            this.reset();
            // we use a sync mode socket instead of async mode one
            this._connected = true;

            //ReceiveServerDataTask = new Task(() =>
            //    {
            //        BeginReceiveDataFromServer();
            //    });


            //bReceiveTaskStarted = true;
            //ReceiveServerDataTask.Start();
        }


        private void socketDataFun(object _arg1)
        {
            //this.ndx = 0;
            //int _local2 = (int)this.socket.bytesAvailable;
            //while ((((((this.ndx < _local2)) && (!((this.nStatus == REQ_ERROR))))) && (this.socket != null)))
            //{
            //    switch (this.nStatus)
            //    {
            //        case REQ_REQUEST:
            //            break;
            //        case REQ_HEADER:
            //            if (!this.read_header(_local2))
            //            {
            //                break;
            //            }
            //            if (!this.parse_header())
            //            {
            //                this.nStatus = REQ_ERROR;
            //                break;
            //            };
            //            this.nStatus = REQ_BODY;
            //            break;
            //        case REQ_BODY:
            //            if (this.parse_body(_local2))
            //            {
            //                this.nStatus = REQ_DONE;
            //            };
            //            break;
            //        default:
            //            return;
            //    };
            //    if (this.nStatus == REQ_ERROR)
            //    {
            //        return;
            //    };
            //    if (this.nStatus == REQ_DONE)
            //    {
            //        if (CrevasseBuffer(this.readpacket, PACKET_HEADER_SIZE, (int)this.readpacket.length, this.enCode, this.m_RecvByteMap) == -1)
            //        {
            //            this.reset();
            //            return;
            //        };
            //        // TODO
            //        // dispatchEvent(new TcpSocketEvent(TcpSocketEvent.SYNC));
            //        this.reset();
            //    };
            //};
        }

        private bool read_header(int _arg1)
        {
            //while ((((this.nreadPos < PACKET_HEADER_SIZE)) && ((this.ndx < _arg1))))
            //{
            //    this.socket.readBytes(this.readpacket, (uint)this.nreadPos, 1);
            //    this.nreadPos++;
            //    this.ndx++;
            //};
            //if (this.nreadPos < PACKET_HEADER_SIZE)
            //{
            //    return (false);
            //};
            return (true);
        }


        private bool parse_header()
        {
            //ByteArray _local1 = new ByteArray();
            //_local1.writeMultiByte("IC", "gb2132");
            //if (((!((this.readpacket[0] == _local1[0]))) || (!((this.readpacket[1] == _local1[1])))))
            //{
            //    _local1 = null;
            //    return (false);
            //};
            //_local1 = null;
            //int _local2 = this.getcmd();
            //if ((((_local2 <= 0)) || ((_local2 >= 0x7D00))))
            //{
            //    return (false);
            //};
            //this.nBodyLen = (uint)this.getbodylen();
            //this.enCode = this.getcode();
            //this.getsequence();
            //if ((((this.nBodyLen >= 0)) && ((this.nBodyLen < (PACKET_BUFFER_SIZE - PACKET_HEADER_SIZE)))))
            //{
            //    return (true);
            //};
            //return (false);

            ByteArray arrBegin = new ByteArray();
            arrBegin.writeMultiByte("IC", "gb2132");
            if (((!((this.readpacket[0] == arrBegin[0]))) || (!((this.readpacket[1] == arrBegin[1])))))
            {
                return false;
            }

            int cmd = this.getcmd();
            if ((((cmd <= 0)) || ((cmd >= 0x7D00))))
            {
                return false;
            }

            this.nBodyLen = (uint)this.getbodylen();
            this.enCode = this.getcode();
            this.getsequence();

            if ((((this.nBodyLen >= 0)) && ((this.nBodyLen < (PACKET_BUFFER_SIZE - PACKET_HEADER_SIZE)))))
            {
                return true;
            }

            return false;
        }

        private bool parse_body(int _arg1)
        {
            //int _local2 = (int)((this.nBodyLen + PACKET_HEADER_SIZE) - this.nreadPos);
            //int _local3 = (_arg1 - this.ndx);
            //if (_local2 <= 0)
            //{
            //    return (true);
            //};
            //if (_local3 <= 0)
            //{
            //    return (false);
            //};
            //uint _local4 = (uint)(((_local3 < _local2)) ? _local3 : _local2);
            //int _local5 = (int)(this.readpacket.length + _local4);
            //if (_local5 > PACKET_BUFFER_SIZE)
            //{
            //    return (false);
            //};
            //this.socket.readBytes(this.readpacket, this.readpacket.position, _local4);
            //this.nreadPos = (int)(this.nreadPos + _local4);
            //this.ndx = (int)(this.ndx + _local4);
            //if (this.nreadPos < (this.nBodyLen + PACKET_HEADER_SIZE))
            //{
            //    this.readpacket.position = (uint)this.nreadPos;
            //    return (false);
            //};
            return (true);
        }

        public static int CrevasseBuffer(ByteArray packet, int startPos, int totalLength, int enCode, ByteArray mapArray)
        {
            //int _local6 = startPos;
            //while (_local6 < totalLength)
            //{
            //    _arg1[_local6] = MapRecvByte(_arg1[_local6], _arg5);
            //    _arg4 = (_arg4 + _arg1[_local6]);
            //    // _arg4;  ???
            //    _arg4 = (_arg4 / 0x0100);
            //    // _arg4;  ???
            //    _local6++;
            //};
            //if (_arg4 != 0)
            //{
            //    return (-1);
            //};

            //return totalLength;

            int pos = startPos;
            while (pos < totalLength)
            {
                packet[pos] = MapRecvByte(packet[pos], mapArray);
                enCode = (enCode + packet[pos]);
                // _arg4;  ???
                enCode = (enCode / 0x0100);
                // _arg4;  ???
                pos++;
            };
            if (enCode != 0)
            {
                return -1;
            };

            return totalLength;
        }

        //public void BeginReceiveDataFromServer()
        //{
        //    while (this._connected)
        //    {
        //        // read header
        //        int bytesRec = this.socket.readBytes(this.readpacket, PACKET_HEADER_SIZE);

        //        // parse header
        //        if (!parse_header())
        //        {
        //            // error
        //            throw new Exception("parse_header error");
        //        }

        //        // read body
        //        bytesRec = this.socket.readBytes(this.readpacket, this.nBodyLen);
        //        this.readpacket.position = PACKET_HEADER_SIZE;

        //        // decrypt body
        //        if (CrevasseBuffer(this.readpacket, PACKET_HEADER_SIZE, (int)this.readpacket.length, this.enCode, this.m_RecvByteMap) == -1)
        //        {
        //            this.reset();
        //            throw new Exception("decrypt error");
        //        };

        //        int cmd = this.getcmd();

        //        this.cmdProcessor.ProcessServerCMD(cmd);

        //        this.reset(); 
        //    }
        //}

        public void BeginReceiveDataFromServer()
        {
            int bufSize = 40960;
            byte[] totalBuff = new byte[bufSize];
            while (this._connected)
            {
                // read all buf data
                int bytesReceive = this.socket.sender.Receive(totalBuff);
                ByteArray total = new ByteArray();
                total.writeArrayBytes(totalBuff);
                int processLen = 0;
                while (processLen < bytesReceive)
                {
                    this.readpacket.writeBytes(total, 0, PACKET_HEADER_SIZE);

                    if (!parse_header())
                    {
                        break;
                    }

                    this.readpacket.writeBytes(total, PACKET_HEADER_SIZE, this.nBodyLen);
                    this.readpacket.position = PACKET_HEADER_SIZE;

                    // decrypt body
                    if (CrevasseBuffer(this.readpacket, PACKET_HEADER_SIZE, (int)this.readpacket.length, this.enCode, this.m_RecvByteMap) == -1)
                    {
                        this.reset();
                        throw new Exception("decrypt error");
                    };

                    int cmd = this.getcmd();

                    //this.cmdProcessor.ProcessServerCMD(cmd);

                    processLen += PACKET_HEADER_SIZE + (int)this.nBodyLen;

                    this.reset();
                }
            }
        }

        private bool needOutputPacket = true;
        private StreamWriter swOutput = null;
        private void InitPacketOutputfile()
        {
            string outputfile = @"packet.txt";

            if (!File.Exists(outputfile))
            {
                using (FileStream fs = File.Create(outputfile))
                {
                    swOutput = new StreamWriter(fs, Encoding.UTF8);
                }
            }
            else
            {
                using (FileStream fs = File.OpenWrite(outputfile))
                {
                    swOutput = new StreamWriter(fs, Encoding.UTF8);
                }
            }
        }

        public void OutputPacketInfo(byte[] bytes, int len)
        {
            if (needOutputPacket)
            {
                //if (swOutput == null)
                //{
                //    InitPacketOutputfile();
                //}

                char[] data = CommonFunction.ByteArrayToCharArray(bytes, 0, len);
                string msg = new string(data);

                player.OutputLogMsg(string.Format("Packet Content : {0}", msg));
            }
        }

        private bool bSkipPacket = true;
        private ByteArray packetBuff = null;
        private static object syncObject = new object();
 
        public void ReceiveServerPacket(byte[] bytes, int len)
        {
            OutputPacketInfo(bytes, len);

            lock (syncObject)
            {
                if (!bSkipPacket)
                {
                    // 一次发送不完的数据，需要拼接
                    packetBuff.appendBytes(bytes, len);
                }
                else
                {
                    // a new usefull packet
                    if (bytes[0] == 0x49 && bytes[1] == 0x43)
                    {
                        packetBuff = new ByteArray();
                        packetBuff.writeBytes(bytes, 0, len);

                        bSkipPacket = false;
                    }
                    else 
                    {
                        throw new Exception("ReceiveServerPacket Error.");
                    }
                }

                ProcessServerPacket();
            }
        }

        public void ProcessServerPacket()
        {
            bool bProcessEnd = false;

            while (!bProcessEnd)
            {
                uint curPos = 0;
                packetBuff.position = curPos;

                byte b1 = (byte)packetBuff.readByte();
                byte b2 = (byte)packetBuff.readByte();

                if (b1 == 0x49 && b2 == 0x43)
                {
                    packetBuff.position = (uint)curPos + 2;
                    int cmd = packetBuff.readShort();

                    packetBuff.position = (uint)curPos + 6;
                    int len = packetBuff.readShort();

                    if (packetBuff.length < PACKET_HEADER_SIZE + len)
                    {
                        packetBuff.position = packetBuff.length;
                        bProcessEnd = true;
                        break;
                    }

                    this.reset();
                    this.readpacket.writeBytes(packetBuff, (uint)curPos, (uint)(PACKET_HEADER_SIZE + len));

                    if (CrevasseBuffer(this.readpacket, PACKET_HEADER_SIZE, (int)this.readpacket.length, this.enCode, this.m_RecvByteMap) == -1)
                    {
                        this.reset();
                        bProcessEnd = true;

                        throw new Exception("CrevasseBuffer Error.");
                    }
                    else
                    {
                        this.packetBuff.TruncateFromHead(PACKET_HEADER_SIZE + len);

                        this.cmdProcessor.ProcessServerCMD(cmd);
                    }

                    if (this.packetBuff.length == 0)
                    {
                        bProcessEnd = true;
                    }
                }
                else
                {
                    bProcessEnd = true;

                    throw new Exception("Parse Error");
                }
            }
        }

        public void writeBegin(int _arg1, int _arg2, int _arg3)
        {
            this.packetlen = 0;
            this.packet.position = 0;
            this.packet.length = 0;
            this.packetbody.position = 0;
            this.packetbody.length = 0;
            this.packet.writeMultiByte("IC", "gb2312");
            this.packet.writeShort(_arg1);
            this.packet.writeByte(_arg2);
            this.packet.writeByte(_arg3);
        }

        public void writeEnd()
        {
            this.packet.writeShort((int)this.packetlen);
            this.packet.writeByte(0);
            this.packet.writeInt(0);
            this.packet.writeBytes(this.packetbody, 0, this.packetlen);
        }

        public void writeErlBegin(int _arg1, int _arg2 = 1, int _arg3 = 1)
        {
            this.packetlen = 0;
            this.packet.position = 0;
            this.packet.length = 0;
            this.packetbody.position = 0;
            this.packetbody.length = 0;
            this.packet.writeShort((int)this.packetlen);
            this.packet.writeMultiByte("BY", "gb2312");
            this.packet.writeByte(_arg2);
            this.packet.writeByte(_arg3);
            this.packet.writeShort(_arg1);
        }

        public void writeErlEnd()
        {
            this.packet.writeByte(0);
            this.packet.position = 0;
            this.packet.writeShort((int)((this.packetlen + ERL_PACKET_HEADER_SIZE) - 2));
            this.packet.position = this.packet.length;
            this.packet.writeBytes(this.packetbody, 0, this.packetlen);
        }

        public void writeCode(int _arg1)
        {
            this.packet.position = 8;
            this.packet.writeByte(_arg1);
        }

        public void writesequence(int _arg1)
        {
            this.packet.position = 9;
            this.packet.writeInt(_arg1);
        }

        public void writeInt(int _arg1)
        {
            this.packetlen = (this.packetlen + 4);
            this.packetbody.writeInt(_arg1);
        }

        public void writeUint(uint _arg1)
        {
            this.packetlen = (this.packetlen + 4);
            this.packetbody.writeUnsignedInt(_arg1);
        }

        public void writeShort(int _arg1)
        {
            this.packetlen = (this.packetlen + 2);
            this.packetbody.writeShort(_arg1);
        }

        public void writeByte(int _arg1)
        {
            this.packetlen = (this.packetlen + 1);
            this.packetbody.writeByte(_arg1);
        }

        public void writeInt64(long _arg1)
        {
            this.packetlen = (this.packetlen + 8);
            int _local2 = (int)(_arg1 % (long)Math.Pow(2, 32));
            int _local3 = (int)(_arg1 / (long)Math.Pow(2, 32));
            this.packetbody.writeInt(_local2);
            this.packetbody.writeInt(_local3);
        }

        public void writeString(string _arg1, string _arg2 ="utf-8")
        {
            ByteArray _local3 = new ByteArray();
            _local3.writeMultiByte(_arg1, _arg2);
            this.packetbody.writeUnsignedInt((_local3.length + 1));
            this.packetlen = (this.packetlen + 4);
            this.packetbody.writeBytes(_local3);
            this.packetbody.writeByte('\0');   // TODO:  Potential bug.
            this.packetlen = (this.packetlen + (_local3.length + 1));
            _local3 = null;
        }

        public void writeBinary(object _arg1)
        {
            ByteArray _local2 = new ByteArray();
            _local2.writeObject(_arg1);
            this.packetbody.writeUnsignedInt(_local2.length);
            this.packetlen = (this.packetlen + 4);
            this.packetbody.writeBytes(_local2);
            this.packetlen = (this.packetlen + _local2.length);
            _local2 = null;
        }

        private void reset()
        {
            this.nStatus = REQ_REQUEST;
            this.nreadPos = 0;
            this.nBodyLen = 0;
            this.readpacket.position = 0;
            this.readpacket.length = 0;
            this.readpacket.Reset();
        }

        public int getcmd()
        {
            this.readpacket.position = 2;
            return (this.readpacket.readShort());
        }

        public int getver()
        {
            this.readpacket.position = 4;
            return (this.readpacket.readByte());
        }

        public int getsubver()
        {
            this.readpacket.position = 5;
            return (this.readpacket.readByte());
        }

        public int getbodylen()
        {
            this.readpacket.position = 6;
            return (this.readpacket.readShort());
        }

        public int getcode()
        {
            this.readpacket.position = 8;
            return (this.readpacket.readByte());
        }

        public int getsequence()
        {
            this.readpacket.position = 9;
            return (this.readpacket.readInt());
        }

        public void readbegin()
        {
            this.readbodypos = PACKET_HEADER_SIZE;
        }

        public int readInt()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 4);
            return (this.readpacket.readInt());
        }

        public long readInt64()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 8);
            uint _local1 = this.readpacket.readUnsignedInt();
            int _local2 = this.readpacket.readInt();
            long _local3 = ((_local2 * (long)Math.Pow(2, 32)) + _local1);
            return (_local3);
        }

        public uint readUint()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 4);
            return (this.readpacket.readUnsignedInt());
        }

        public short readShort()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 2);
            return (this.readpacket.readShort());
        }

        public int readByte()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 1);
            return (this.readpacket.readByte());
        }

        public string readString()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 4);
            uint _local1 = this.readpacket.readUnsignedInt();
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (int)(this.readbodypos + _local1);
            string contentWithZero =  (this.readpacket.readMultiByte(_local1, "utf-8"));

            if (contentWithZero.Length > 1)
            {
                contentWithZero = contentWithZero.Substring(0, contentWithZero.Length - 1);
            }

            return contentWithZero;
        }

        public string readgb2132String()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 4);
            uint _local1 = this.readpacket.readUnsignedInt();
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (int)(this.readbodypos + _local1);
            return (this.readpacket.readMultiByte(_local1, "gb2132"));
        }

        public object readBinary()
        {
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (this.readbodypos + 4);
            uint _local1 = this.readpacket.readUnsignedInt();
            this.readpacket.position = (uint)this.readbodypos;
            this.readbodypos = (int)(this.readbodypos + _local1);
            ByteArray _local2 = new ByteArray();
            this.readpacket.readBytes(_local2, 0, _local1);
            return (_local2.readObject());
        }

        public bool sendcmd(bool _arg1 = true)
        {
            int _local2;
            if (this._connected)
            {
                _local2 = EncryptBuffer(this.packet, PACKET_HEADER_SIZE, (int)this.packet.length, this.m_SendByteMap);
                this.writeCode(_local2);
                if (_arg1)
                {
                    this.writesequence(this.sequence++);
                };
                this.socket.writeBytes(this.packet, 0, (uint)(this.packetlen + PACKET_HEADER_SIZE));
                this.socket.flush();
                this.packet.Reset();
                this.packetbody.Reset();
                return (true);
            };
            return (false);
        }

        public bool sendErlCmd()
        {
            int _local1;
            if (this._connected)
            {
                _local1 = EncryptBuffer(this.packet, ERL_PACKET_HEADER_SIZE, (int)this.packet.length, this.m_SendByteMap);
                this.writeCode(_local1);
                this.socket.writeBytes(this.packet, 0, (this.packetlen + ERL_PACKET_HEADER_SIZE));
                this.socket.flush();
                return (true);
            };
            return (false);
        }

        public void close()
        {
            this.clearEvent();
            if (this._connected)
            {
                this._connected = false;
                this.socket.close();
                this.socket = null;
            };
        }

        private void connectFun(object _arg1)
        {
            this._connected = true;
            this.clearEvent();

            // TODO: Design an event system in C#
            //this.socket.addEventListener(ProgressEvent.SOCKET_DATA, this.socketDataFun);
            //this.socket.addEventListener(Event.CLOSE, this.closeFun);

            // TODO: What if comment this ?
            //dispatchEvent(new TcpSocketEvent(TcpSocketEvent.CONNECT));
        }

        private void closeFun(object _arg1)
        {
            this._connected = false;
            // TODO: What if comment this ?
            //dispatchEvent(new TcpSocketEvent(TcpSocketEvent.CLOSE));
        }

        private void securityerrfun(object _arg1)
        {
            this.clearEvent();
            this._connected = false;
            if(this.socket != null)
            {
                this.socket.close();
            }
            this.socket = null;
            // TODO: What if comment this ?
            // dispatchEvent(new TcpSocketEvent(TcpSocketEvent.SECURITYERROR));
        }

        private void errorFun(object _arg1)
        {
            this.clearEvent();
            this._connected = false;
            if(this.socket != null)
            {
                this.socket.close();
            }
            this.socket = null;
            // TODO: What if comment this ?
            //dispatchEvent(new TcpSocketEvent(TcpSocketEvent.ERROR));
        }


        private void clearEvent()
        {
            // leave all events related to future.
            //if (this.socket != null)
            //{
            //    if (this.socket.hasEventListener(IOErrorEvent.IO_ERROR))
            //    {
            //        this.socket.removeEventListener(IOErrorEvent.IO_ERROR, this.errorFun);
            //    };
            //    if (this.socket.hasEventListener(Event.CONNECT))
            //    {
            //        this.socket.removeEventListener(Event.CONNECT, this.connectFun);
            //    };
            //    if (this.socket.hasEventListener(ProgressEvent.SOCKET_DATA))
            //    {
            //        this.socket.removeEventListener(ProgressEvent.SOCKET_DATA, this.socketDataFun);
            //    };
            //    if (this.socket.hasEventListener(Event.CLOSE))
            //    {
            //        this.socket.removeEventListener(Event.CLOSE, this.closeFun);
            //    };
            //    if (this.socket.hasEventListener(SecurityErrorEvent.SECURITY_ERROR))
            //    {
            //        this.socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityerrfun);
            //    };
            //};
        }

        public string getHost()
        {
            return (this._host);
        }

        public int getPort()
        {
            return (this._port);
        }

        public bool getConnecState()
        {
            return (this._connected);
        }
    }
}//package com.boyaa.texas.net.socket

